/**
 * MySurfaceView.java
 * Copyright(C) 2014
 * creator:cuiran 2014-6-23 下午6:12:34
 */
package org.videolan.vlc.gui.video;

import java.util.ArrayList;
import java.util.Map;

import org.videolan.libvlc.EventHandler;
import org.videolan.libvlc.IVideoPlayer;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.LibVlcException;
import org.videolan.libvlc.LibVlcUtil;
import org.videolan.libvlc.Media;
import org.videolan.vlc.AudioServiceController;
import org.videolan.vlc.R;
import org.videolan.vlc.TipsUtil;
import org.videolan.vlc.Util;
import org.videolan.vlc.WeakHandler;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Presentation;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.media.MediaRouter;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.SurfaceHolder.Callback;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;

/**
 *  
 * @author cuiran
 * @version 1.0.0
 */
public class MySurfaceView extends SurfaceView implements IVideoPlayer {
	    public final static String TAG = "VLC/MySurfaceView";

		
		private Context mContext;
	    // Internal intent identifier to distinguish between internal launch and
	    // external intent.
	    private final static String PLAY_FROM_VIDEOGRID = "org.videolan.vlc.gui.video.PLAY_FROM_VIDEOGRID";

	    private SurfaceView mSurface;
	    private SurfaceView mSubtitlesSurface;
	    private SurfaceHolder mSurfaceHolder;
	    private SurfaceHolder mSubtitlesSurfaceHolder;
	    private FrameLayout mSurfaceFrame;
	    private MediaRouter mMediaRouter;
	    private MediaRouter.SimpleCallback mMediaRouterCallback;
	    private LibVLC mLibVLC;
	    private String mLocation;

	    private static final int SURFACE_BEST_FIT = 0;
	    private static final int SURFACE_FIT_HORIZONTAL = 1;
	    private static final int SURFACE_FIT_VERTICAL = 2;
	    private static final int SURFACE_FILL = 3;
	    private static final int SURFACE_16_9 = 4;
	    private static final int SURFACE_4_3 = 5;
	    private static final int SURFACE_ORIGINAL = 6;
	    private int mCurrentSize = SURFACE_BEST_FIT;

	    /** Overlay */
	    private View mOverlayHeader;
	    private View mOverlayOption;
	    private View mOverlayProgress;
	    private View mOverlayBackground;
	    private static final int OVERLAY_TIMEOUT = 4000;
	    private static final int OVERLAY_INFINITE = 3600000;
	    private static final int FADE_OUT = 1;
	    private static final int SHOW_PROGRESS = 2;
	    private static final int SURFACE_SIZE = 3;
	    private static final int AUDIO_SERVICE_CONNECTION_SUCCESS = 5;
	    private static final int AUDIO_SERVICE_CONNECTION_FAILED = 6;
	    private static final int FADE_OUT_INFO = 4;
	    private boolean mDragging;
	    private boolean mShowing;
	    private int mUiVisibility = -1;
	    private SeekBar mSeekbar;
	    private TextView mTitle;
	    private TextView mSysTime;
	    private TextView mBattery;
	    private TextView mTime;
	    private TextView mLength;
	    private TextView mInfo;
	    private ImageView mLoading;
	    private TextView mLoadingText;
	    private ImageButton mPlayPause;
	    private ImageButton mBackward;
	    private ImageButton mForward;
	    private boolean mEnableJumpButtons;
	    private boolean mEnableBrightnessGesture;
	    private boolean mDisplayRemainingTime = false;
	    private int mScreenOrientation;
	    private ImageButton mAudioTrack;
	    private ImageButton mSubtitle;
	    private ImageButton mLock;
	    private ImageButton mSize;
	    private ImageButton mMenu;
	    private boolean mIsLocked = false;
	    private int mLastAudioTrack = -1;
	    private int mLastSpuTrack = -2;

	    /**
	     * For uninterrupted switching between audio and video mode
	     */
	    private boolean mSwitchingView;
	    private boolean mEndReached;
	    private boolean mCanSeek;

	    // Playlist
	    private int savedIndexPosition = -1;

	    // size of the video
	    private int mVideoHeight;
	    private int mVideoWidth;
	    private int mVideoVisibleHeight;
	    private int mVideoVisibleWidth;
	    private int mSarNum;
	    private int mSarDen;

	    //Volume
	    private AudioManager mAudioManager;
	    private int mAudioMax;
	    private OnAudioFocusChangeListener mAudioFocusListener;

	    //Touch Events
	    private static final int TOUCH_NONE = 0;
	    private static final int TOUCH_VOLUME = 1;
	    private static final int TOUCH_BRIGHTNESS = 2;
	    private static final int TOUCH_SEEK = 3;
	    private int mTouchAction;
	    private int mSurfaceYDisplayRange;
	    private float mTouchY, mTouchX, mVol;

	    // Brightness
	    private boolean mIsFirstBrightnessGesture = true;

	    // Tracks & Subtitles
	    private Map<Integer,String> mAudioTracksList;
	    private Map<Integer,String> mSubtitleTracksList;
	    /**
	     * Used to store a selected subtitle; see onActivityResult.
	     * It is possible to have multiple custom subs in one session
	     * (just like desktop VLC allows you as well.)
	     */
	    private final ArrayList<String> mSubtitleSelectedFiles = new ArrayList<String>();

	    // Whether fallback from HW acceleration to SW decoding was done.
	    private boolean mDisabledHardwareAcceleration = false;
	    private int mPreviousHardwareAccelerationMode;
	/**
	 * @param context
	 */
	public MySurfaceView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		initVideoView(context);
	}

	/**
	 * @param context
	 * @param attrs
	 */
	public MySurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		initVideoView(context);
	}

	/**
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
		initVideoView(context);
	}
	
	/**
	 * init VideoView
	 * 2014-6-23 下午6:15:49
	 * @param ctx
	 *
	 */
	 private void initVideoView(Context ctx) {
		this.mContext=ctx;
		 if (LibVlcUtil.isJellyBeanMR1OrLater()) {
	            // Get the media router service (miracast)
//	            mMediaRouter = (MediaRouter) ctx.getSystemService(Context.MEDIA_ROUTER_SERVICE);
//	            mMediaRouterCallback = new MediaRouter.SimpleCallback() {
//	                @Override
//	                public void onRoutePresentationDisplayChanged(
//	                        MediaRouter router, MediaRouter.RouteInfo info) {
//	                    Log.d(TAG, "onRoutePresentationDisplayChanged: info="
//	                            + info);
//	                    
//	                }
//	            };
	        }
//		 	setSurfaceSize(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);
          
		 
		    SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(ctx);
		    SurfaceHolder surfaceHolder= getHolder();
		    String chroma = pref.getString("chroma_format", "");
	        if(LibVlcUtil.isGingerbreadOrLater() && chroma.equals("YV12")) {
	        	surfaceHolder.setFormat(ImageFormat.YV12);
	        } else if (chroma.equals("RV16")) {
	        	surfaceHolder.setFormat(PixelFormat.RGB_565);
	        } else {
	        	surfaceHolder.setFormat(PixelFormat.RGBX_8888);
	        }
	        surfaceHolder.addCallback(mSurfaceCallback);
	        mSurface=this;
		    setFocusable(true);
		    setFocusableInTouchMode(true);
		    requestFocus();
		     /* Services and miscellaneous */
	        mAudioManager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);
	        mAudioMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
	        
	        /* Loading view */
	        LayoutInflater factory = LayoutInflater.from(mContext);
//			//得到自定义对话框
			View loadView = factory.inflate(R.layout.loading, null);
		
	        mLoading = (ImageView)loadView.findViewById(R.id.player_overlay_loading);
	        mLoadingText = (TextView)loadView.findViewById(R.id.player_overlay_loading_text);
	        TipsUtil.alertCustomDialog(mContext, loadView);
	        
//	        mLoading=new ImageView(mContext);
//	        mLoadingText=new TextView(mContext);
	        startLoadingAnimation();
	        
	        EventHandler em = EventHandler.getInstance();
	        em.addHandler(eventHandler);
	        
		    if (ctx instanceof Activity)
		      ((Activity) ctx).setVolumeControlStream(AudioManager.STREAM_MUSIC);
		    
		    try {
	            mLibVLC = Util.getLibVlcInstance();
	        } catch (LibVlcException e) {
	            Log.d(TAG, "LibVLC initialisation failed");
	            return;
	        }
		    bindAudioService();
	 }
	 
	  /**
	     * Start the video loading animation.
	     */
	    private void startLoadingAnimation() {
	        AnimationSet anim = new AnimationSet(true);
	        RotateAnimation rotate = new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
	        rotate.setDuration(800);
	        rotate.setInterpolator(new DecelerateInterpolator());
	        rotate.setRepeatCount(RotateAnimation.INFINITE);
	        anim.addAnimation(rotate);
	        mLoading.startAnimation(anim);
	        mLoadingText.setVisibility(View.VISIBLE);
	    }

	    /**
	     * Stop the video loading animation.
	     */
	    private void stopLoadingAnimation() {
	        mLoading.setVisibility(View.INVISIBLE);
	        mLoading.clearAnimation();
	        mLoadingText.setVisibility(View.GONE);
	        TipsUtil.closeCustomDialog();
	    }
	 
	 public void bindAudioService(){
		 AudioServiceController.getInstance().bindAudioService(mContext,
	                new AudioServiceController.AudioServiceConnectionListener() {
	            @Override
	            public void onConnectionSuccess() {
	                mHandler.sendEmptyMessage(AUDIO_SERVICE_CONNECTION_SUCCESS);
	            }

	            @Override
	            public void onConnectionFailed() {
	                mHandler.sendEmptyMessage(AUDIO_SERVICE_CONNECTION_FAILED);
	            }
	        });
	 }
	   /**
     *
     */
	 public void play() {
        mLibVLC.play();
        mSurface.setKeepScreenOn(true);
    }

    /**
     *
     */
    public void pause() {
        mLibVLC.pause();
        mSurface.setKeepScreenOn(false);
    }
	 
	 public void setVideoPath(String path) {
		 mLocation=LibVLC.PathToURI(path);
		 if (mLocation != null && mLocation.length() > 0){
			  AudioServiceController.getInstance().stop(); // Stop the previous playback.
			  mLibVLC.setMediaList();
			  mLibVLC.getMediaList().add(new Media(mLibVLC, mLocation));
			  savedIndexPosition = mLibVLC.getMediaList().size() - 1;
//			  mLibVLC.setHardwareAcceleration(hardwareAcceleration)
			  mLibVLC.playIndex(savedIndexPosition);
		 }
	 }
	 public void setVideoURI(Uri uri) {
		 
	 }
	 
	  /**
	     *  Handle libvlc asynchronous events
	     */
	 private final Handler eventHandler = new MySurfaceViewEventHandler(this);
	 
	 private static class MySurfaceViewEventHandler extends WeakHandler<MySurfaceView> {
	        public MySurfaceViewEventHandler(MySurfaceView owner) {
	            super(owner);
	        }
	        @Override
	        public void handleMessage(Message msg) {
	        	MySurfaceView activity = getOwner();
	            if(activity == null) return;
	            // Do not handle events if we are leaving the VideoPlayerActivity
	            if (activity.mSwitchingView) return;

	            switch (msg.getData().getInt("event")) {
	                case EventHandler.MediaParsedChanged:
	                    Log.i(TAG, "MediaParsedChanged");
	                    if (activity.mLibVLC.getVideoTracksCount() < 1) {
	                        Log.i(TAG, "No video track, open in audio mode");
//	                        activity.switchToAudioMode();
	                    }
	                    break;
	                case EventHandler.MediaPlayerPlaying:
	                    Log.i(TAG, "MediaPlayerPlaying");
	                    activity.stopLoadingAnimation();
	                    break;
	                case EventHandler.MediaPlayerPaused:
	                    Log.i(TAG, "MediaPlayerPaused");
	                    break;
	                case EventHandler.MediaPlayerStopped:
	                    Log.i(TAG, "MediaPlayerStopped");
	                   
	                    break;
	                case EventHandler.MediaPlayerEndReached:
	                    Log.i(TAG, "MediaPlayerEndReached");
	                    activity.endReached();
	                    break;
	                case EventHandler.MediaPlayerVout:
//	                    activity.handleVout(msg);
	                    break;
	                case EventHandler.MediaPlayerPositionChanged:
	                    if (!activity.mCanSeek)
	                        activity.mCanSeek = true;
	                    //don't spam the logs
	                    break;
	                case EventHandler.MediaPlayerEncounteredError:
	                    Log.i(TAG, "MediaPlayerEncounteredError");
//	                    activity.encounteredError();
	                    break;
	                case EventHandler.HardwareAccelerationError:
	                    Log.i(TAG, "HardwareAccelerationError");
	                 
	                    break;
	                default:
	                    Log.e(TAG, String.format("Event not handled (0x%x)", msg.getData().getInt("event")));
	                    break;
	            }
	           
	        }
	        
	 }
	 
	 	/**
	     * Handle resize of the surface and the overlay
	     */
	 private final Handler mHandler = new MySurfaceViewHandler(this);
	    
	  private static class MySurfaceViewHandler extends WeakHandler<MySurfaceView> {
	       
		  public MySurfaceViewHandler(MySurfaceView owner) {
	            super(owner);
	      
		  }
	        
		  @Override
	        public void handleMessage(Message msg) {
			  MySurfaceView activity = getOwner();
	            if(activity == null) // WeakReference could be GC'ed early
	                return;

	            switch (msg.what) {
	               
	                case SURFACE_SIZE:
	                    activity.changeSurfaceSize();
	                    break;
	              
	            }
	        }
	  }
	
	@Override
	public void setSurfaceSize(int width, int height, int visible_width,
			int visible_height, int sar_num, int sar_den) {
		// TODO Auto-generated method stub
		 if (width * height == 0)
	            return;

	        // store video size
	        mVideoHeight = height;
	        mVideoWidth = width;
	        mVideoVisibleHeight = visible_height;
	        mVideoVisibleWidth  = visible_width;
	        mSarNum = sar_num;
	        mSarDen = sar_den;
	        Message msg = mHandler.obtainMessage(SURFACE_SIZE);
	        mHandler.sendMessage(msg);
	}

	 /* (non-Javadoc)
	 * @see android.view.SurfaceView#onMeasure(int, int)
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		 Log.i(TAG, "onMeasure >>>>>>>>>>>>>>>>>>>>>>>");
		int width = getDefaultSize(0, widthMeasureSpec); 
        int height = getDefaultSize(0, heightMeasureSpec); 
        
        setMeasuredDimension(width, height); 
	}
	
	private void endReached() {
        if(true) {
            Log.d(TAG, "Found a video playlist, expanding it");
            eventHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                	setVideoPath("/sata/media/jiuzai.mpg");
                }
            }, 1000);
        } else {
            /* Exit player when reaching the end */
            mEndReached = true;
            
        }
    }


	private void changeSurfaceSize() {
	        int sw;
	        int sh;

	        // get screen size
	            sw = ((Activity)mContext).getWindow().getDecorView().getWidth();
	            sh = ((Activity)mContext).getWindow().getDecorView().getHeight();
	     
	        double dw = sw, dh = sh;
	        boolean isPortrait;

	        // getWindow().getDecorView() doesn't always take orientation into account, we have to correct the values
	         isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
	     
	         Log.e(TAG, "dw="+dw+",dh="+dh);
	        if (sw > sh && isPortrait || sw < sh && !isPortrait) {
	            dw = sh;
	            dh = sw;
	        }

	        // sanity check
	        if (dw * dh == 0 || mVideoWidth * mVideoHeight == 0) {
	            Log.e(TAG, "Invalid surface size");
	            return;
	        }

	        // compute the aspect ratio
	        double ar, vw;
	        if (mSarDen == mSarNum) {
	            /* No indication about the density, assuming 1:1 */
	            vw = mVideoVisibleWidth;
	            ar = (double)mVideoVisibleWidth / (double)mVideoVisibleHeight;
	        } else {
	            /* Use the specified aspect ratio */
	            vw = mVideoVisibleWidth * (double)mSarNum / mSarDen;
	            ar = vw / mVideoVisibleHeight;
	        }

	        // compute the display aspect ratio
	        double dar = dw / dh;

	        switch (mCurrentSize) {
	            case SURFACE_BEST_FIT:
	                if (dar < ar)
	                    dh = dw / ar;
	                else
	                    dw = dh * ar;
	                break;
	            case SURFACE_FIT_HORIZONTAL:
	                dh = dw / ar;
	                break;
	            case SURFACE_FIT_VERTICAL:
	                dw = dh * ar;
	                break;
	            case SURFACE_FILL:
	                break;
	            case SURFACE_16_9:
	                ar = 16.0 / 9.0;
	                if (dar < ar)
	                    dh = dw / ar;
	                else
	                    dw = dh * ar;
	                break;
	            case SURFACE_4_3:
	                ar = 4.0 / 3.0;
	                if (dar < ar)
	                    dh = dw / ar;
	                else
	                    dw = dh * ar;
	                break;
	            case SURFACE_ORIGINAL:
	                dh = mVideoVisibleHeight;
	                dw = vw;
	                break;
	        }

	        SurfaceView surface;
	        SurfaceHolder surfaceHolder;
	        surface = mSurface;
	        surfaceHolder = mSurfaceHolder;
	           
	        // force surface buffer size
	        surfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);
	    
	        // set display size
	        LayoutParams lp = surface.getLayoutParams();
	        lp.width  = (int) Math.ceil(dw * mVideoWidth / mVideoVisibleWidth);
	        lp.height = (int) Math.ceil(dh * mVideoHeight / mVideoVisibleHeight);
	        lp.width  = this.getWidth();
	        lp.height = this.getHeight();
	        Log.e(TAG, "width="+lp.width +",height="+lp.height);
	        
	        Log.e(TAG, "width1="+this.getWidth() +",height2="+this.getHeight());
	        surface.setLayoutParams(lp);
	        surface.invalidate();
	    }
	  /**
     * attach and disattach surface to the lib
     */
    private final SurfaceHolder.Callback mSurfaceCallback = new Callback() {
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            if(format == PixelFormat.RGBX_8888)
                Log.d(TAG, "Pixel format is RGBX_8888");
            else if(format == PixelFormat.RGB_565)
                Log.d(TAG, "Pixel format is RGB_565");
            else if(format == ImageFormat.YV12)
                Log.d(TAG, "Pixel format is YV12");
            else
                Log.d(TAG, "Pixel format is other/unknown");
            mLibVLC.attachSurface(holder.getSurface(),MySurfaceView.this);
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
        	mSurfaceHolder = holder;
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mLibVLC.detachSurface();
        }
    };

   
	
	
}
